{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 循环"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "循环的作用在于将一段代码重复执行多次。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## while 循环"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    while <condition>:\n",
    "        <statesments>\n",
    "\n",
    "**Python**会循环执行`<statesments>`，直到`<condition>`不满足为止。\n",
    "\n",
    "例如，计算数字`0`到`1000000`的和："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "499999500000\n"
     ]
    }
   ],
   "source": [
    "i = 0\n",
    "total = 0\n",
    "while i < 1000000:\n",
    "    total += i\n",
    "    i += 1\n",
    "print total"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前提到，空容器会被当成 `False` ，因此可以用 `while` 循环来读取容器中的所有元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Perform King Lear\n",
      "Perform Macbeth\n",
      "Perform Hamlet\n"
     ]
    }
   ],
   "source": [
    "plays = set(['Hamlet', 'Macbeth', 'King Lear'])\n",
    "while plays:\n",
    "    play = plays.pop()\n",
    "    print 'Perform', play"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "循环每次从 `plays` 中弹出一个元素，一直到 `plays` 为空为止。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## for 循环"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "    for <variable> in <sequence>:\n",
    "        <indented block of code>\n",
    "\n",
    "`for` 循环会遍历完`<sequence>`中所有元素为止\n",
    "\n",
    "上一个例子可以改写成如下形式："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Perform King Lear\n",
      "Perform Macbeth\n",
      "Perform Hamlet\n"
     ]
    }
   ],
   "source": [
    "plays = set(['Hamlet', 'Macbeth', 'King Lear'])\n",
    "for play in plays:\n",
    "    print 'Perform', play"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 `for` 循环时，注意尽量不要改变 `plays` 的值，否则可能会产生意想不到的结果。\n",
    "\n",
    "之前的求和也可以通过 `for` 循环来实现："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4999950000\n"
     ]
    }
   ],
   "source": [
    "total = 0\n",
    "for i in range(100000):\n",
    "    total += i\n",
    "print total"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然而这种写法有一个缺点：在循环前，它会生成一个长度为 `100000` 的临时列表。\n",
    "\n",
    "生成列表的问题在于，会有一定的时间和内存消耗，当数字从 `100000` 变得更大时，时间和内存的消耗会更加明显。\n",
    "\n",
    "为了解决这个问题，我们可以使用 `xrange` 来代替 `range` 函数，其效果与`range`函数相同，但是 `xrange` 并不会一次性的产生所有的数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4999950000\n"
     ]
    }
   ],
   "source": [
    "total = 0\n",
    "for i in xrange(100000):\n",
    "    total += i\n",
    "print total"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "比较一下两者的运行时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 loops, best of 3: 40.7 ms per loop\n"
     ]
    }
   ],
   "source": [
    "%timeit for i in xrange(1000000): i = i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 loops, best of 3: 96.6 ms per loop\n"
     ]
    }
   ],
   "source": [
    "%timeit for i in range(1000000): i = i"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看出，`xrange` 用时要比 `range` 少。 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## continue 语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "遇到 `continue` 的时候，程序会返回到循环的最开始重新执行。\n",
    "\n",
    "例如在循环中忽略一些特定的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "values = [7, 6, 4, 7, 19, 2, 1]\n",
    "for i in values:\n",
    "    if i % 2 != 0:\n",
    "        # 忽略奇数\n",
    "        continue\n",
    "    print i/2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## break 语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "遇到 `break` 的时候，程序会跳出循环，不管循环条件是不是满足："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start\n",
      "process\n",
      "process\n",
      "process\n"
     ]
    }
   ],
   "source": [
    "command_list = ['start', \n",
    "                'process', \n",
    "                'process',\n",
    "                'process', \n",
    "                'stop', \n",
    "                'start', \n",
    "                'process', \n",
    "                'stop']\n",
    "while command_list:\n",
    "    command = command_list.pop(0)\n",
    "    if command == 'stop':\n",
    "        break\n",
    "    print(command)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在遇到第一个 `'stop'` 之后，程序跳出循环。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## else语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "与 `if` 一样， `while` 和 `for` 循环后面也可以跟着 `else` 语句，不过要和`break`一起连用。\n",
    "\n",
    "- 当循环正常结束时，循环条件不满足， `else` 被执行；\n",
    "- 当循环被 `break` 结束时，循环条件仍然满足， `else` 不执行。\n",
    "\n",
    "不执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found: 7\n"
     ]
    }
   ],
   "source": [
    "values = [7, 6, 4, 7, 19, 2, 1]\n",
    "for x in values:\n",
    "    if x <= 10:\n",
    "        print 'Found:', x\n",
    "        break\n",
    "else:\n",
    "    print 'All values greater than 10'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "执行："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All values greater than 10\n"
     ]
    }
   ],
   "source": [
    "values = [11, 12, 13, 100]\n",
    "for x in values:\n",
    "    if x <= 10:\n",
    "        print 'Found:', x\n",
    "        break\n",
    "else:\n",
    "    print 'All values greater than 10'"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
